<script setup lang="ts">
import { ref, computed, watch } from "vue"
import { CheckboxValueType } from "ant-design-vue/es/checkbox/interface"
import Button from "../button/Button.vue"
import CheckboxGroup from "../checkbox-group/CheckboxGroup.vue"
import { Filter } from "../rest-filter"
import Modal from "../modal/Modal.vue"
import Table from "../table/Table.vue"


/**
 * @module FilterSetting
 *
 * 本组件实现一个过滤器筛选和排序的功能，通过filters属性传入所有可用的过滤器；
 * 使用checkbox对过滤器进行筛选；
 * 使用sortable对筛选后的过滤器进行排序；
 * 使用model将筛选排序后的过滤器返还给调用方。
 */

export interface Props {
  uniqueKey?: string // 用来确定filters成员的唯一性
  filters: Filter[]
}

// 返回过滤排序后的过滤器
// 选中的过滤器hidden属性为false，隐藏的过滤器hidden属性为true
// 将按照排序顺序排列，隐藏的过滤器排在选中的过滤器后面
const model = defineModel<Filter[]>({ default: () => [] })

// 默认使用key属性作为列表成员的唯一性判断依据
const props = withDefaults(defineProps<Props>(), {
  uniqueKey: "prop",
  filters: () => [],
})

const emits = defineEmits(['openFilterSettings'])


// 排序后的元素
const sortedFilters = computed<Filter[]>({
  get() {
    return model.value.filter((filter) => !filter.hidden)
  },
  set(values: Filter[]) {
    const sorted = values.map((filter) => ({ ...filter, hidden: false }))

    const keys = values.map((filter) => filter[props.uniqueKey])
    const hidden = props.filters
      .filter((filter) => !keys.includes(filter[props.uniqueKey]))
      .map((filter) => ({ ...filter, hidden: true }))

    model.value = sorted.concat(hidden)
  },
})

const dataSource = computed(() => {
  return sortedFilters.value
})

const reloadTable = ref(false)
const columns = [{
  title: '名称',
  dataIndex: 'label',
  key: 'label',
}]

const getDragData = (e:any) => {
  // 不能直接把val.list赋给sortedFilters，下拉搜索框有丢失数据的问题
  const arr:Filter[] = []
  const { list } = e
  list.forEach((el:any) => {
    sortedFilters.value.filter((filter) => !filter.hidden).forEach(el1 => {
      if (el.label === el1.label) {
        arr.push(el1)
      }
    })
  })

  sortedFilters.value = arr
}

// 获取排序项的key作为选中项参数
const selectedItems = computed({
  get() {
    return sortedFilters.value.map((filter) => filter[props.uniqueKey])
  },
  // 因为选中项元素的顺序和sortedFilters中元素的顺序不一定相同
  // 需要先移除没有选中的项，再在sortedFilters末尾添加新增项
  set(values: CheckboxValueType[]) {
    // 删除已经移除的项目
    let selectedKeys = sortedFilters.value
      .map((filter) => filter[props.uniqueKey])
      .filter((item) => values.includes(item))

    // 如果result没有元素，则直接复制选中项
    if (selectedKeys.length === 0) {
      selectedKeys = values
    } else {
      // 添加新增的项目
      values.forEach((item) => {
        // 检查选中项在结果中是否存在
        const exists = selectedKeys.includes(item)
        if (!exists) {
          // 如果不存在，添加到结果中
          selectedKeys.push(item)
        }
      })
    }

    sortedFilters.value = []
    const arr:Filter[] = []
    // 保留之前移动过的顺序
    selectedKeys.forEach(selectedKey => {
      props.filters.forEach((filter) => {
        if (selectedKey===filter[props.uniqueKey]) {
          arr.push(filter)
        }
      })
    })
    sortedFilters.value = arr
    resetTable()
  },
})

// 表格重置一下
// 不重置的话，拖拽的时候会报错(找不到拖拽那一项，导致拖不动)
function resetTable() {
  reloadTable.value = false
  setTimeout(() => {
    reloadTable.value = true
  });
}

watch(
  () => props.filters,
  (values: Filter[]) => {
    selectedItems.value = values
      .filter((filter) => !filter.hidden)
      .map((filter) => filter[props.uniqueKey])
  },
  { immediate: true },
)

// 选项列表
const checkboxOptions = computed(() => {
  return props.filters.map((item) => ({
    label: item.label,
    value: item[props.uniqueKey],
  }))
})

// 监听已选项，修改排序项目
function onCheckboxGroupChange(values: CheckboxValueType[]) {
  selectedItems.value = values
}

function onClickReset() {
  sortedFilters.value = props.filters.filter((filter) => !filter.hidden)
  resetTable()
}

const showModal = ref(false)

const open = () => {
  emits('openFilterSettings')
}
</script>

<template>
  <Button type="text" class="pc-filter-settings-btn" @click="showModal = true;open()">
    <h-icon-filter />
  </Button>
  <Modal
    v-if="showModal"
    v-model="showModal"
    title="设置过滤字段"
    :force-render="true"
    :closable="true"
    :footer="null"
    :mask="true"
    :width="856"
    class="filter-setting-modal"
  >
    <div class="filter-settings-container">
      <!-- 选择器 -->
      <CheckboxGroup
        class="pc-flex-0 pc-h-full"
        :model-value="selectedItems"
        :options="checkboxOptions"
        :divide="false"
        @change="onCheckboxGroupChange"
      />
      <!-- 列表 -->
      <div class="pc-pl-6 pc-gap-2 pc-w-60 pc-min-w-60 pc-text-xs">
        <div class="pc-flex pc-justify-between pc-items-center pc-mb-3 pc-text-xs">
          <div>当前选定的字段</div>
          <Button size="sm" type="link" @click="onClickReset">重置</Button>
        </div>
        <Table
          v-if="reloadTable"
          :columns="columns"
          :data-source="dataSource"
          :drag="true"
          :pagination="false"
          row-key="prop"
          size="mini"
          class="filter-settings-container-table"
          @dragData="getDragData"></Table>
      </div>
    </div>
  </Modal>
</template>

<style scoped>
.filter-settings-container {
  @apply pc-flex pc-justify-between pc-divide-x pc-overflow-hidden pc-min-h-56 pc-text-xs pc-leading-none;
}

:deep(.filter-settings-container .ant-checkbox-wrapper>span:last-child)  {
  @apply pc-w-24 pc-whitespace-pre-wrap pc-box-content pc-text-xs;
}

:deep(.filter-settings-container .ant-checkbox-wrapper),
:deep(.filter-settings-container .ant-checkbox-wrapper .ant-checkbox) {
  @apply pc-items-start pc-self-start pc-leading-none pc-text-xs;
}

:deep(.filter-settings-container .filter-settings-container-table .ant-table) {
  @apply pc-text-xs;
}

:deep(.filter-settings-container .filter-settings-container-table .ant-table-container) {
  @apply pc-h-fit;
}

:deep(.filter-settings-container .ant-btn.ant-btn-sm.ant-btn-inline) {
  @apply pc-p-0 pc-h-auto;
}

:deep(.filter-settings-container .ant-table-wrapper .ant-table-mini .drag-icon-pack) {
  margin-top: 6px;
}

button.pc-filter-settings-btn {
  @apply pc-text-xl;
  padding-left: 5px;
  padding-right: 5px;
  color: #86909C;
}
</style>
